d6cca2
@@ -19,6 +19,7 @@
 package org.apache.hadoop.hbase.master.handler;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 
@@ -27,6 +28,7 @@
import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.hbase.HRegionInfo;
 import org.apache.hadoop.hbase.Server;
+import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableNotDisabledException;
 import org.apache.hadoop.hbase.TableNotFoundException;
 import org.apache.hadoop.hbase.catalog.CatalogTracker;
@@ -36,7 +38,11 @@
import org.apache.hadoop.hbase.master.AssignmentManager;
 import org.apache.hadoop.hbase.master.BulkAssigner;
 import org.apache.hadoop.hbase.master.HMaster;
 import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
+import org.apache.hadoop.hbase.master.RegionPlan;
+import org.apache.hadoop.hbase.master.RegionStates;
+import org.apache.hadoop.hbase.master.ServerManager;
 import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Pair;
 import org.apache.zookeeper.KeeperException;
 import org.cloudera.htrace.Trace;
 
@@ -50,6 +56,7 @@
public class EnableTableHandler extends EventHandler {
   private final String tableNameStr;
   private final AssignmentManager assignmentManager;
   private final CatalogTracker ct;
+  private boolean retainAssignment = false;
 
   public EnableTableHandler(Server server, byte [] tableName,
       CatalogTracker catalogTracker, AssignmentManager assignmentManager,
@@ -60,6 +67,7 @@
public class EnableTableHandler extends EventHandler {
     this.tableNameStr = Bytes.toString(tableName);
     this.ct = catalogTracker;
     this.assignmentManager = assignmentManager;
+    this.retainAssignment = skipTableStateCheck;
     // Check if table exists
     if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) {
       throw new TableNotFoundException(Bytes.toString(tableName));
@@ -111,10 +119,12 @@
public class EnableTableHandler extends EventHandler {
       LOG.error("Error trying to enable the table " + this.tableNameStr, e);
     } catch (KeeperException e) {
       LOG.error("Error trying to enable the table " + this.tableNameStr, e);
+    } catch (InterruptedException e) {
+      LOG.error("Error trying to enable the table " + this.tableNameStr, e);
     }
   }
 
-  private void handleEnableTable() throws IOException, KeeperException {
+  private void handleEnableTable() throws IOException, KeeperException, InterruptedException {
     // I could check table is disabling and if so, not enable but require
     // that user first finish disabling but that might be obnoxious.
 
@@ -123,18 +133,18 @@
public class EnableTableHandler extends EventHandler {
     boolean done = false;
     // Get the regions of this table. We're done when all listed
     // tables are onlined.
-    List<HRegionInfo> regionsInMeta;
-    regionsInMeta = MetaReader.getTableRegions(this.ct, tableName, true);
-    int countOfRegionsInTable = regionsInMeta.size();
-    List<HRegionInfo> regions = regionsToAssign(regionsInMeta);
+    List<Pair<HRegionInfo, ServerName>> tableRegionsAndLocations = MetaReader
+        .getTableRegionsAndLocations(this.ct, tableName, true);
+    int countOfRegionsInTable = tableRegionsAndLocations.size();
+    List<HRegionInfo> regions = regionsToAssignWithServerName(tableRegionsAndLocations);
     int regionsCount = regions.size();
     if (regionsCount == 0) {
       done = true;
     }
     LOG.info("Table '" + this.tableNameStr + "' has " + countOfRegionsInTable
       + " regions, of which " + regionsCount + " are offline.");
-    BulkEnabler bd = new BulkEnabler(this.server, regions,
-      countOfRegionsInTable);
+    BulkEnabler bd = new BulkEnabler(this.server, regions, countOfRegionsInTable,
+        this.retainAssignment);
     try {
       if (bd.bulkAssign()) {
         done = true;
@@ -158,19 +168,31 @@
public class EnableTableHandler extends EventHandler {
   }
 
   /**
-   * @param regionsInMeta This datastructure is edited by this method.
-   * @return The <code>regionsInMeta</code> list minus the regions that have
-   * been onlined; i.e. List of regions that need onlining.
+   * @param regionsInMeta
+   * @return List of regions neither in transition nor assigned.
    * @throws IOException
    */
-  private List<HRegionInfo> regionsToAssign(
-    final List<HRegionInfo> regionsInMeta)
-  throws IOException {
-    final List<HRegionInfo> onlineRegions =
-      this.assignmentManager.getRegionStates()
-        .getRegionsOfTable(tableName);
-    regionsInMeta.removeAll(onlineRegions);
-    return regionsInMeta;
+  private List<HRegionInfo> regionsToAssignWithServerName(
+      final List<Pair<HRegionInfo, ServerName>> regionsInMeta) throws IOException {
+    ServerManager serverManager = ((HMaster) this.server).getServerManager();
+    List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
+    RegionStates regionStates = this.assignmentManager.getRegionStates();
+    for (Pair<HRegionInfo, ServerName> regionLocation : regionsInMeta) {
+      HRegionInfo hri = regionLocation.getFirst();
+      ServerName sn = regionLocation.getSecond();
+      if (!regionStates.isRegionInTransition(hri) && !regionStates.isRegionAssigned(hri)) {
+        if (this.retainAssignment && sn != null && serverManager.isServerOnline(sn)) {
+          this.assignmentManager.addPlan(hri.getEncodedName(), new RegionPlan(hri, null, sn));
+        }
+        regions.add(hri);
+      } else {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Skipping assign for the region " + hri + " during enable table "
+              + hri.getTableNameAsString() + " because its already in tranition or assigned.");
+        }
+      }
+    }
+    return regions;
   }
 
   /**
@@ -180,12 +202,14 @@
public class EnableTableHandler extends EventHandler {
     private final List<HRegionInfo> regions;
     // Count of regions in table at time this assign was launched.
     private final int countOfRegionsInTable;
+    private final boolean retainAssignment;
 
     BulkEnabler(final Server server, final List<HRegionInfo> regions,
-        final int countOfRegionsInTable) {
+        final int countOfRegionsInTable, boolean retainAssignment) {
       super(server);
       this.regions = regions;
       this.countOfRegionsInTable = countOfRegionsInTable;
+      this.retainAssignment = retainAssignment;
     }
 
     @Override
@@ -193,7 +217,9 @@
public class EnableTableHandler extends EventHandler {
       boolean roundRobinAssignment = this.server.getConfiguration().getBoolean(
           "hbase.master.enabletable.roundrobin", false);
 
-      if (!roundRobinAssignment) {
+      // In case of masterRestart always go with single assign.  Going thro
+      // roundRobinAssignment will use bulkassign which may lead to double assignment.
+      if (retainAssignment || !roundRobinAssignment) {
         for (HRegionInfo region : regions) {
           if (assignmentManager.getRegionStates()
               .isRegionInTransition(region)) {
@@ -202,7 +228,12 @@
public class EnableTableHandler extends EventHandler {
           final HRegionInfo hri = region;
           pool.execute(Trace.wrap(new Runnable() {
             public void run() {
-              assignmentManager.assign(hri, true);
+              if (retainAssignment) {
+                // Already plan is populated.
+                assignmentManager.assign(hri, true, false, false);
+              } else {
+                assignmentManager.assign(hri, true);
+              }
             }
           }));
         }
